package com.bowlong.net.proto.gen;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

import com.bowlong.lang.PStr;
import com.bowlong.lang.StrEx;
import com.bowlong.text.Encoding;
import com.bowlong.tool.Lib2;
import com.bowlong.util.MapEx;
import com.bowlong.util.NewList;
import com.bowlong.util.NewMap;
import com.bowlong.util.StrBuilder;

@SuppressWarnings({ "unused", "resource", "rawtypes", "unchecked" })
public class Bio2GCSharp extends Lib2 {

	/**
	 * @param args
	 * @return
	 */
	public static String b2g(Class<?> c, boolean src) {
		B2Class B2C = c.getAnnotation(B2Class.class);
		String namespace = "";
		if (B2C != null) {
			namespace = B2C.namespace();
		}

		// String p = "gen_b2g";
		String p = (src ? "src/" : "") + "gen_b2g";
		if (namespace != null && !namespace.isEmpty()) {
			p = p + "/" + namespace;
		}
		File path = new File(p);
		if (!path.exists())
			path.mkdirs();

		Class<?>[] classes = c.getDeclaredClasses();
		StrBuilder sb = new StrBuilder();

		sb.pn("using System;");
		sb.pn("using System.Collections;");
		sb.pn("using System.Collections.Generic;");
		sb.pn("");
		sb.pn("using Toolkit;");
		sb.pn("");

		sb.pn("namespace ${1} {", c.getSimpleName());
		if (B2G.haveMethods(classes)) {
			sb.pn("");
			sb.pn("public interface TcpChannel {");
			sb.pn("    void send(string method, Hashtable map);");
			sb.pn("}");
			sb.pn("");
		}
		sb.pn(excel(c, classes));
		sb.pn("");
		for (Class<?> class1 : classes) {
			String sname = class1.getSimpleName();
			if (B2G.isData(class1)) {
				String f = class1.getSimpleName();
				if (B2G.isConstant(class1)) {
					g2beanConstant(class1, namespace, sb);
				} else {
					g2bean(class1, namespace, sb);
				}
			}
		}

		for (Class<?> class1 : classes) {
			String sname = class1.getSimpleName();
			if (B2G.isServer(class1)) {
				g2s_call(class1, namespace, sb);
			}
		}

		String sname = c.getSimpleName();
		sb.pn("}");

		writeFile(p + "/" + sname + ".cs", sb.toString());

		System.out.println(sb);
		return sb.toString();
	}

	public static String excel(Class<?> c, Class<?>[] classes) {
		if (!B2G.isExcel(c))
			return "";
		String cn = c.getSimpleName();
		StrBuilder sb = new StrBuilder();
		StrBuilder sb1 = new StrBuilder();
		StrBuilder sb2 = new StrBuilder();
		String className = "Sheets";
		sb.pn("public class ${1} {", className);
		for (Class<?> c1 : classes) {
			if (B2G.isSheet(c1)) {
				String cname = c1.getSimpleName();
				String sheetName = B2G.getSheetName(c1);
				String cname2 = StrEx.left(cname, cname.length() - 1);
				sb1.ap("$[1], ", sheetName);
				sb2.ap("$[1], ", sheetName + ".pb.bytes");
				sb.pn("    public const string SHEET_${1} = $[2];",
						upperS(sheetName), sheetName);
				sb.pn("    public const string FN_${1} = $[2];",
						upperS(sheetName), sheetName + ".pb.bytes");
				sb.pn("");
			}
		}
		if (sb1.len() > 2)
			sb1.removeRight(2);
		if (sb2.len() > 2)
			sb2.removeRight(2);
		String str1 = sb1.toString();
		String str2 = sb2.toString();
		sb.pn("    public static string[] sheets = {${1}};", str1);
		sb.pn("    public static string[] files = {${1}};", str2);

		sb.pn("    public static void init(string name, byte[] buff) {");
		sb.pn("        switch (name) {");
		for (Class<?> c1 : classes) {
			if (B2G.isSheet(c1)) {
				String cname = c1.getSimpleName();
				String sheetName = B2G.getSheetName(c1);
				String cname2 = StrEx.left(cname, cname.length() - 1);
				sb.pn("            case SHEET_${1}:{", upperS(sheetName));
				sb.pn("                ${1}.loadToCache(buff);", cname);
				sb.pn("                break;");
				sb.pn("            }");
			}
		}
		sb.pn("            default: break;");
		sb.pn("        }");
		sb.pn("");
		sb.pn("    }");
		sb.pn("}");
		String result = sb.toString();
		return result;
	}

	public static void g2bean(Class<?> c, String namespace, StrBuilder sb) {
		Field[] fs = c.getDeclaredFields();
		String cname = c.getSimpleName();
		int hcname = cname.hashCode();
		// sb.pn("package gen_b2g${1}.bean;", StrEx.isEmpty(namespace) ? "" :
		// "."
		// + namespace);
		// sb.pn("");
		// sb.pn("import java.io.*;");
		// sb.pn("import java.util.*;");
		// sb.pn("");
		// sb.pn("import com.bowlong.util.*;");
		sb.pn("public class ${1} {", cname);
		// sb.pn("    public const int _CID = ${1};", hcname);
		// sb.pn("");
		StrBuilder sb0 = new StrBuilder();
		StrBuilder sb1 = new StrBuilder();
		int i = 0;
		for (Field field : fs) {
			String t = B2G.getCsType(field);
			String s = field.getName();
			if (s.contains("$"))
				continue;
			String remark = B2G.getRemark(field);
			if (field.getType().equals(List.class)) {
				boolean isBasic = B2G.isCsBasicType(field);
				String gtype = B2G.getCsListType(field);
				if (isBasic) {
					sb.pn("    public ArrayList ${1}; ${2}", s, remark);

					if (i == 0) {
						sb0.ap("ArrayList ${2}", t, s);
						sb1.ap("${1}", s);
					} else {
						sb0.ap(", ArrayList ${2}", t, s);
						sb1.ap(", ${1}", s);
					}

				} else if (gtype != null && !gtype.isEmpty()) {
					sb.pn("    public ${1}<${3}> ${2}; ${4}", t, s, gtype,
							remark);
					
					if (i == 0) {
						sb0.ap("${1}<${3}> ${2}", t, s, gtype);
						sb1.ap("${1}", s);
					} else {
						sb0.ap(", ${1}<${3}> ${2}", t, s, gtype);
						sb1.ap(", ${1}", s);
					}

				}
			} else {
				if (t.contains("string")) {
					sb.pn("    public ${1} ${2} = \"\"; ${3}", t, s, remark);

				} else if (t.contains("int") || t.contains("long")) {
					sb.pn("    protected ${1} _${2}; ${3}", t, s, remark);

				} else {
					sb.pn("    public ${1} ${2}; ${3}", t, s, remark);
				}
				
				if (i == 0) {
					sb0.ap("${1} ${2}", t, s);
					sb1.ap("${1}", s);
				} else {
					sb0.ap(", ${1} ${2}", t, s);
					sb1.ap(", ${1}", s);
				}
			}
			
			i++;

		}
		sb.pn("");
		for (Field field : fs) {
			String t = B2G.getCsType(field);
			String s = field.getName();
			if (s.contains("$"))
				continue;

			String remark = B2G.getRemark(field);
			if (field.getType().equals(List.class)) {
				String gtype = B2G.getListType(field);
				if (gtype != null && !gtype.isEmpty()) {
				}
			} else {
				if (t.contains("string")) {
				} else if (t.contains("int") || t.contains("long")) {
					sb.pn("    public ${1} ${2} {", t, s);
					sb.pn("        set { _${2} = EnDe.en (value); }", t, s);
					sb.pn("        get { return EnDe.de (_${2}); }", t, s);
					sb.pn("    }");
				} else {
				}
			}
		}
		// ///////
		sb.pn("");
		for (Field field : fs) {
			B2Field a = field.getAnnotation(B2Field.class);
			String s = field.getName();
			String t = B2G.getType(field);
			if (s.contains("$"))
				continue;

			if (field.getType().equals(List.class)) {
				String gtype = B2G.getListType(field);
				boolean isBtype = B2G.isBType(gtype);
				if (gtype != null && !gtype.isEmpty() && !isBtype) {
					sb.pn("    public ArrayList ${1}_maps() {", s);
					sb.pn("        ArrayList r = new ArrayList();");
					sb.pn("        if(${1} == null) return r;", s);
					sb.pn("        foreach(${1} _e in ${2}) {", gtype, s);
					sb.pn("            Hashtable e = _e.toMap();");
					sb.pn("            if(e == null) continue;");
					sb.pn("            r.Add(e);");
					sb.pn("        }");
					sb.pn("        return r;");
					sb.pn("    }");
					sb.pn("");

					sb.pn("    public static List<${2}> maps_${1}(ArrayList maps) {",
							s, gtype);
					sb.pn("        List<${1}> r = new List<${1}>();", gtype);
					sb.pn("        foreach(Hashtable _e in maps) {", gtype, s);
					sb.pn("            ${1} e = ${1}.parse(_e);", gtype);
					sb.pn("            if(e == null) continue;");
					sb.pn("            r.Add(e);");
					sb.pn("        }");
					sb.pn("        return r;");
					sb.pn("    }");
					sb.pn("");

				}
			}
		}
		// ///////

		sb.pn("");
		sb.pn("    public Hashtable toMap() {");
		sb.pn("        Hashtable r = new Hashtable();");
		// sb.pn("        r.Add(${1}, _CID);", B2G.BEAN);
		for (Field field : fs) {
			String t = B2G.getType(field);
			String gm = B2G.getMapType(t);
			String s = field.getName();
			int hs = s.hashCode();
			if (s.contains("$"))
				continue;

			if (field.getType().equals(List.class)) {
				String gtype = B2G.getListType(field);
				boolean isBtype = B2G.isBType(gtype);
				if (gtype != null && !gtype.isEmpty() && !isBtype) {
					sb.pn("        r.Add(${1}, ${2}_maps());", hs, s);
				} else {
					sb.pn("        r.Add(${1}, ${2});", hs, s);
				}
			} else {
				if (gm.equals("getObject")) {
					sb.pn("        r.Add(${1}, ${2}.toMap());", hs, s);
				} else {
					sb.pn("        r.Add(${1}, ${2});", hs, s);
				}
			}
		}
		sb.pn("        return r;");
		sb.pn("    }");
		sb.pn("");

		sb.pn("");
		sb.pn("    public static ${1} parse (byte[] buf) {", cname);
		sb.pn("        NewMap map = (NewMap) B2InputStream.readObject (new System.IO.MemoryStream (buf));");
		sb.pn("        return parse (map);");
		sb.pn("    }");
		sb.pn("");

		sb.pn("");
		sb.pn("    public static ${1} parse(Hashtable map) {", cname);
		sb.pn("        if(map == null) return null;");
		sb.pn("");
		sb.pn("        NewMap map2 = NewMap.create(map);");
		sb.pn("        ${1} r = new ${1}();", cname);
		for (Field field : fs) {
			String t = B2G.getCsType(field);
			String gm = B2G.getCsMapType(t);
			String s = field.getName();
			int hs = s.hashCode();
			if (s.contains("$"))
				continue;

			if (field.getType().equals(List.class)) {
				String gtype = B2G.getListType(field);
				boolean isBtype = B2G.isBType(gtype);
				if (gtype != null && !gtype.isEmpty() && !isBtype) {
					sb.pn("        r.${1} = maps_${1}( map2.getList(${3}) );",
							s, gm, hs, gtype);
				} else {
					sb.pn("        r.${1} = map2.${2}(${3});", s, gm, hs);
				}
			} else {
				if (gm.equals("getObject")) {
					sb.pn("        r.${1} = ${2}.parse(map2.getNewMap(${3}));",
							s, t, hs);
				} else {
					sb.pn("        r.${1} = map2.${2}(${3});", s, gm, hs);
				}
			}
		}
		sb.pn("        return r;");
		sb.pn("    }");
		sb.pn("");

		sb.pn("");
		sb.pn("    public static ${1} create (${2}) {", cname, sb0.toString());
		sb.pn("        return new ${1}(${2});", cname, sb1.toString());
		sb.pn("    }");
		sb.pn("");
		sb.pn("    public ${1}() {}", cname, cname);
		sb.pn("");
		sb.pn("    public ${1}(${3}) {", cname, cname, sb0.toString());
//		sb.pn("        ${1} r = new ${1}();", cname);
		for (Field field : fs) {
			String t = B2G.getCsType(field);
			String gm = B2G.getCsMapType(t);
			String s = field.getName();
			int hs = s.hashCode();
			if (s.contains("$"))
				continue;

			sb.pn("        this.${1} = ${1};", s);
		}
//		sb.pn("        return this;");
		sb.pn("    }");
		sb.pn("");

		sb.pn("    public static ${1} setVar(${1} r2, ${3}) {", cname, cname, sb0.toString());
		sb.pn("        return r2.setVar(${1});", sb1.toString());
		sb.pn("    }");
		sb.pn("");
		
		sb.pn("    public ${1} setVar(${2}) {", cname, sb0.toString());
//		sb.pn("        ${1} r = new ${1}();", cname);
		for (Field field : fs) {
			String t = B2G.getCsType(field);
			String gm = B2G.getCsMapType(t);
			String s = field.getName();
			int hs = s.hashCode();
			if (s.contains("$"))
				continue;

			sb.pn("        this.${1} = ${1};", s);
		}
		sb.pn("        return this;");
		sb.pn("    }");
		sb.pn("");
		if (B2G.isSheet(c)) {
			String sheetIndexs = B2G.getSheetIndexs(c);
			String sheetName = B2G.getSheetName(c);
			String cname2 = StrEx.left(cname, cname.length() - 1);
			sb.pn("    public const string sheetName = $[1];", sheetName);
			sb.pn("    public const string fn = $[1];", sheetName + ".pb.bytes");
			sb.pn("    public static string path(string path) {");
			sb.pn("        return path + fn;");
			sb.pn("    }");
			sb.pn("");

			sb.pn("    /////////////////// ");
			sb.pn("    public static ${1} CACHED;", cname);
			sb.pn("    public static ${1}[] CACHE_ARRAY;", cname2);
			sb.pn("    static Dictionary<int, int> Q1_CACHED = new Dictionary<int, int>();");
			sb.pn("    static Dictionary<int, HashSet<int>> QCACHED = new Dictionary<int, HashSet<int>>();");
			sb.pn("");
			sb.pn("");
			sb.pn("    static ${1} hit1(MultiKey2 mkey) {", cname2);
			sb.pn("        int key = mkey.GetHashCode();");
			sb.pn("        if(!Q1_CACHED.ContainsKey(key))");
			sb.pn("            return null;");
			sb.pn("        int id = Q1_CACHED[key];");
			sb.pn("        return CACHE_ARRAY[id];");
			sb.pn("    }");
			sb.pn("");
			sb.pn("    static List<${1}> hits(MultiKey2 mkey) {", cname2);
			sb.pn("        int key = mkey.GetHashCode();");
			sb.pn("        List<${1}> r2 = new List<${1}>();", cname2);
			sb.pn("        if(!QCACHED.ContainsKey(key))");
			sb.pn("            return r2;");
			sb.pn("        HashSet<int> list = QCACHED[key];");
			sb.pn("        if (list == null)");
			sb.pn("            return r2;");
			sb.pn("        foreach (int id in list)");
			sb.pn("            r2.Add(CACHE_ARRAY[id]);");
			sb.pn("        return r2;");
			sb.pn("    }");
			sb.pn("");
			sb.pn("    static void cache(MultiKey2 mkey, ${1} v) {", cname2);
			sb.pn("        if (mkey == null || v == null)");
			sb.pn("            return;");
			sb.pn("        int key = mkey.GetHashCode();");
			sb.pn("        HashSet<int> list = null;");
			sb.pn("        Q1_CACHED[key] = v.ID;");
			sb.pn("    }");
			sb.pn("");
			sb.pn("    static void cache(MultiKey2 mkey, List<${1}> vals) {", cname2);
			sb.pn("        if (mkey == null || vals == null || vals.Count <= 0)");
			sb.pn("            return;");
			sb.pn("        int key = mkey.GetHashCode();");
			sb.pn("        HashSet<int> list = null;");
			sb.pn("        if(QCACHED.ContainsKey(key)) {");
			sb.pn("            list = QCACHED[key];");
			sb.pn("            list.Clear();");
			sb.pn("        } else {");
			sb.pn("            list = new HashSet<int>();");
			sb.pn("            QCACHED[key] = list;");
			sb.pn("        }");
			sb.pn("");
			sb.pn("        foreach (${1} v in vals)", cname2);
			sb.pn("            list.Add(v.ID);");
			sb.pn("    }");
			sb.pn("");
			sb.pn("    public static void Clear() {");
			sb.pn("        CACHED = null;");
			sb.pn("        CACHE_ARRAY = null;");
			sb.pn("        QCACHED.Clear();");
			sb.pn("    }");
			sb.pn("    /////////////////// ");
			sb.pn("    public static void loadToCache(byte[] buff) {");
			sb.pn("        loadToCache(buff, false);");
			sb.pn("    }");
			sb.pn("    public static void loadToCache(byte[] buff, bool force) {");
			sb.pn("        if(!force && CACHED != null)");
			sb.pn("            return;");
			sb.pn("        CACHED = parse(buff);");
			sb.pn("        loadToCache(CACHED);");
			sb.pn("        QCACHED.Clear();");
			sb.pn("    }");
			sb.pn("    /////////////////// ");
			sb.pn("    public static void loadToCache(${1} data) {", cname);
			sb.pn("        ${1} _DATA = (${1})data.datas[data.datas.Count - 1];",
					cname2);
			sb.pn("        int MAXID = _DATA.ID;");
			sb.pn("        CACHE_ARRAY = new ${1}[MAXID + 1];", cname2);
			sb.pn("        foreach (${1} e in data.datas) {", cname2);
			sb.pn("            CACHE_ARRAY[e.ID] = e;");

			// 索引查询器
			List<Map> indexs = parseList(sheetIndexs);
			for (Map map : indexs) {
				String type = MapEx.getString(map, "type"); // ix , ux
				List<Map> fields = MapEx.getList(map, "fields");
				String cps = getSheetIndexParams(fields);
				if (type.equals("ux")) {
					sb.pn("            { ");
					sb.pn("              MultiKey2 mkey = new MultiKey2(${1});", cps);
					sb.pn("              cache(mkey, e);");
					sb.pn("            }");
				}
			}
			
			sb.pn("        }");
			sb.pn("    }");
			sb.pn("    /////////////////// ");
			sb.pn("    public static ${1} getById(int id) {", cname2);
			sb.pn("        return CACHE_ARRAY[id];");
			sb.pn("    }");
			sb.pn("    public static List<${1}> getAll() {", cname2);
			sb.pn("        return CACHED.datas;");
			sb.pn("    }");

			// 索引查询器
//			List<Map> indexs = parseList(sheetIndexs);
			for (Map map : indexs) {
				String type = MapEx.getString(map, "type"); // ix , ux
				List<Map> fields = MapEx.getList(map, "fields");
				String indexMethod = getSheetIndexMethod(cname2, map);
				String rst = getSheetIndexReturn(cname2, type);
				String rstInit = getSheetIndexReturnInit(cname2, type);
				String eqs = getSheetIndexMethodEq(fields);
				String cps = getSheetCallParams(fields);
				sb.pn("    public static ${1} {", indexMethod);
				sb.pn("        MultiKey2 mkey = new MultiKey2(${1});", cps);
				if (type.equals("ix")) {
					sb.pn("        ${1} r2 = hits(mkey);", rst);
					sb.pn("        if(r2 != null && r2.Count > 0)");
					sb.pn("            return r2;");
					// sb.pn("        r2 = ${1};", rstInit);
				} else {
					sb.pn("        ${1} r2 = hit1(mkey);", rst);
					sb.pn("        if(r2 != null)");
					sb.pn("            return r2;");
				}
				sb.pn("");
//				sb.pn("        ${1} r2 = ${2};", rst, rstInit);
				sb.pn("        List<${1}> datas = getAll();", cname2);
				sb.pn("        foreach (${1} e in datas) {", cname2);
				sb.pn("            if(${1}) {", eqs);
				if (type.equals("ix"))
					sb.pn("                r2.Add(e);");
				else {
					sb.pn("                r2 = e;");
					sb.pn("                break;");
				}
				sb.pn("            }");
				sb.pn("        }");
				sb.pn("        cache(mkey, r2);");
				sb.pn("        return r2;");
				sb.pn("    }");
			}
		}
		sb.pn("}");
	}

	public static void g2beanConstant(Class<?> c, String namespace,
			StrBuilder sb) {
		Field[] fs = c.getDeclaredFields();
		String cname = c.getSimpleName();
		sb.pn("public class ${1} {", cname);
		for (Field field : fs) {
			String t = B2G.getCsType(field);
			String s = field.getName();

			if (s.contains("$"))
				continue;

			String remark = B2G.getRemark(field);
			String def = B2G.getDef(field);
			if (field.getType().equals(List.class)) {
				String gtype = B2G.getListType(field);
				if (gtype != null && !gtype.isEmpty()) {
					continue;
				}
			} else {
				if (t.contains("string")) {
					sb.pn("    public const ${1} ${2} = \"${4}\"; ${3}", t, s,
							remark, def);

				} else {
					sb.pn("    public const ${1} ${2} = ${4}; ${3}", t, s,
							remark, def);
				}
			}
		}
		sb.pn("}");
	}

	// 生成客户端接口
	public static void g2s_call(Class<?> c, String namespace, StrBuilder sb) {
		String sname = c.getSimpleName();
		Method[] methods = c.getMethods();
		String cname = c.getSimpleName();
		sb.pn("public abstract class Call${1} {", cname);

		sb.pn("");
		sb.pn("    public static int __uid;");
		sb.pn("    public TcpChannel chn;");
		sb.pn("    public Call${1}(TcpChannel chn) {", sname);
		sb.pn("        this.chn = chn;");
		sb.pn("    }");
		sb.pn("");
		for (Method m : methods) {
			if (!B2G.isServer(m))
				continue;

			String remark = B2G.getRemark(m);
			String srtype = B2G.getReturnType(m);
			String mname = B2G.getNethodName(m);
			int hmname = mname.hashCode();
			NewList<NewMap<String, String>> params = B2G.getParameters(m);
			StrBuilder sb1 = new StrBuilder();
			for (NewMap<String, String> m1 : params) {
				String mykey = (String) (m1.getKey().equals("boolean") ? "bool"
						: m1.getKey());
				mykey = (String) (mykey.equals("List") ? "ArrayList" : mykey);
				mykey = (String) (mykey.equals("Map") ? "Hashtable" : mykey);
				String myvar = (String) m1.getValue();
				boolean isOut = B2G.isOut(m, myvar);
				if (isOut) {

				} else {
					sb1.ap("${1} ${2}, ", mykey, myvar);
				}
			}
			if (sb1.length() > 2) {
				sb1.removeRight(2);
			}

			// 需要实现的逻辑函数
			sb.pn("    // ${1}", remark);
			sb.pn("    public void ${1}(${2}) {", mname, sb1);
			sb.pn("        Hashtable _map = new Hashtable();");
			sb.pn("        _map.Add(-100, __uid);  // __uid");
			sb.pn("        _map.Add(${1}, ${2});  // cmd:${3}", B2G.METHOD,
					hmname, mname);
			for (NewMap<String, String> m1 : params) {
				String key = (String) m1.getKey();
				String val = (String) m1.getValue();
				String p = B2G.getMapType(key);
				String hval = val.hashCode() + "";
				boolean isOut = B2G.isOut(m, val);
				if (isOut) {

				} else {
					if (p.equals("getList")) {
						String oType = B2G.getOType(m, val);
						String mType = B2G.getMapType(oType);
						if (mType.equals("getObject")) {
							sb.pn("        { // Lsit对象(${1})", val);
							sb.pn("            NewList ${1}_list = new NewList();",
									val);
							sb.pn("            _map.Add(${1}, ${2}_list);",
									hval, val);
							sb.pn("            foreach(${1} obj in ${2}) {",
									oType, val);
							sb.pn("                ${1}_list.add(obj.toMap());",
									val, oType);
							sb.pn("            }");
							sb.pn("        }");
							val += "_list";
						} else {
							sb.pn("        _map.Add(${1}, ${2});", hval, val);
						}
					} else if (B2G.getMapType(key).equals("getObject")) {
						sb.pn("        _map.Add(${1}, ${2}.toMap());", hval,
								val);
					} else {
						sb.pn("        _map.Add(${1}, ${2});", hval, val);
					}
				}
			}
			sb.pn("        chn.send($[1], _map);", mname);
			sb.pn("    }");
			sb.pn("");
		}

		StrBuilder sb2 = new StrBuilder();
		for (Method m : methods) {
			String rtype = B2G.getReturnType(m);
			if (B2G.isServer(m) && rtype.equals("void"))
				continue;

			String mname = B2G.getNethodName(m);
			int hmname = mname.hashCode();
			sb2.ap("${1},", hmname);
		}
		sb2.removeRight(1);
		String s = sb2.toString();

		sb.pn("");
		sb.pn("    public static NewSet CMD = NewSet.create(${1});", s);
		sb.pn("");
		sb.pn("    public static bool withIn(Hashtable map) {");
		sb.pn("        int cmd = MapEx.getInt(map, ${1});", B2G.METHOD);
		sb.pn("        return CMD.Contains(cmd);");
		sb.pn("    }");
		sb.pn("");

		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("    // 逻辑分发");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("");
		sb.pn("    public void disp(NewMap map) {");
		sb.pn("        int cmd = MapEx.getInt(map, ${1});", B2G.METHOD);
		sb.pn("        disp(cmd, map);");
		sb.pn("    }");
		sb.pn("    public void disp(int cmd, NewMap map) {");
		sb.pn("        switch (cmd) {");
		for (Method m : methods) {
			String remark = B2G.getRemark(m);
			String srtype = B2G.getReturnType(m);
			String mname = B2G.getNethodName(m);
			int hmname = mname.hashCode();
			if (B2G.isServer(m)) {
				if (!srtype.equals("void")) {
					sb.pn("            case ${1}: { //  ${2}", hmname, remark);
					sb.pn("                __onCallback_${1}(cmd, map);", mname);
					sb.pn("                return;");
					sb.pn("            }");
				}
			} else {
				sb.pn("            case ${1}: { //  ${2}", hmname, remark);
				sb.pn("                __onCall_${1}(cmd, map);", mname);
				sb.pn("                return;");
				sb.pn("            }");
			}
		}
		sb.pn("        }");
		sb.pn("        throw new Exception(\" cmd: \" + cmd + \":\" + map + \" not found processor.\");");
		sb.pn("    }");
		sb.pn("");
		sb.pn("");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("    // 参数解析");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("");
		for (Method m : methods) {
			String remark = B2G.getRemark(m);
			// String oType = B2G.getOType(m);
			String srtype = B2G.getReturnType(m);
			String mname = B2G.getNethodName(m);
			int hmname = mname.hashCode();
			NewList<NewMap<String, String>> params = B2G.getParameters(m);

			// 解析参数函数
			if (B2G.isServer(m)) {
				if (!srtype.equals("void")) {
					sb.pn("    // ${1}", remark);
					sb.pn("    private void __onCallback_${1}(int cmd, NewMap map2) {",
							mname);
					String mx = B2G.getCsMapType(srtype);
					//sb.pn("        NewMap map2 = NewMap.create(map);");
					sb.pn("        Hashtable retVal = map2.getMap(${1});",
							B2G.RETURN_STAT);
					sb.pn("        ReturnStatus rst = ReturnStatus.parse(retVal);");
					boolean haveIsOut = false;
					StrBuilder msb = new StrBuilder();
					for (NewMap<String, String> m1 : params) {
						String key = (String) m1.getKey();
						String val = (String) m1.getValue();
						String hval = val.hashCode() + "";
						String p = B2G.getMapType(key);
						boolean isOut = B2G.isOut(m, val);
						if (isOut) {
							if (p.equals("getObject")) {
								sb.pn("        ${1} ${2} = null; // def var",
										key, val, hval);
								msb.ap("${1}, ", val);
								haveIsOut = true;
							}
						}
					}
					if (haveIsOut) {
						sb.pn("        if(rst.succ >= 0) {");

						for (NewMap<String, String> m1 : params) {
							String key = (String) m1.getKey();
							String val = (String) m1.getValue();
							String hval = val.hashCode() + "";
							String p = B2G.getMapType(key);
							boolean isOut = B2G.isOut(m, val);
							if (isOut) {
								if (p.equals("getObject")) {
									sb.pn("          ${2} = ${1}.parse(map2.getNewMap(${3}));",
											key, val, hval);
								}
							}
						}
						sb.pn("        }");
					}
					sb.pn("        on${1}(cmd, ${2}rst);", upper1(mname), msb);
					sb.pn("    }");
				}
			} else {
				sb.pn("    // ${1}", remark);
				sb.pn("    private void __onCall_${1}(int cmd, NewMap map2) {",
						mname);
				//sb.pn("        NewMap map2 = NewMap.create(map);");
				sb.pn("");
				StrBuilder sb1 = new StrBuilder();
				for (NewMap<String, String> m1 : params) {
					String key = (String) m1.getKey();
					String val = (String) m1.getValue();
					String hval = val.hashCode() + "";
					String p = B2G.getCsMapType(key);
					if (p.equals("getObject")) {
						sb.pn("        ${1} ${2} = ${1}.parse(map2.getNewMap(${3}));",
								key, val, hval);
					} else {
						if (B2G.getMapType(key).equals("getList")) {
							key = "ArrayList";
						}
						key = key.toLowerCase().equals("boolean") ? "bool"
								: key;
						key = key.equals("String") ? "string" : key;
						sb.pn("        ${1} ${2} = map2.${3}(${4});", key, val,
								p, hval);
						if (B2G.getMapType(key).equals("getList")) {
							String oType = B2G.getOType(m, val);
							String mType = B2G.getCsMapType(oType);

							sb.pn("		ArrayList ${1}_list = new NewList();", val);
							sb.pn("		{");
							sb.pn("			// Lsit对象(${1})", val);
							sb.pn("			foreach (object obj in ${1}) {", val);
							if (mType.equals("getObject")) {
								sb.pn("				${1}_list.Add(${2}.parse((Hashtable)obj));",
										val, oType);
							} else {
								sb.pn("				${1}_list.Add(obj);", val);
							}
							sb.pn("			}");
							sb.pn("		}");
							val += "_list";
						}
					}
					sb1.ap("${1}, ", val);
				}
				if (sb1.length() > 2)
					sb1.removeRight(2);
				sb.pn("");
				if (srtype.equals("void")) {
					sb.pn("        on${1}(cmd, ${2});", upper1(mname), sb1);
				} else {
					sb.pn("        ReturnStatus rst = on${1}(cmd, ${2});",
							upper1(mname), sb1, srtype);
					sb.pn("        Hashtable result = new NewMap();");
					sb.pn("        result.Add(${1}, ${2});", B2G.METHOD, hmname);
					sb.pn("        result.Add(${1}, rst.toMap());",
							B2G.RETURN_STAT);
					sb.pn("        chn.send(result);");
				}
				sb.pn("    }");
			}
			sb.pn("");
		}

		sb.pn("");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("    // 需要实现的接口");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("");
		sb.pn("    public abstract void OnExcept(Exception e, int stat, string msg);");
		sb.pn("");
		for (Method m : methods) {
			String remark = B2G.getRemark(m);
			// String oType = B2G.getOType(m);
			String srtype = B2G.getReturnType(m);
			String mname = B2G.getNethodName(m);
			NewList<NewMap<String, String>> params = B2G.getParameters(m);

			// 解析参数函数
			sb.pn("    // ${1}", remark);
			if (B2G.isServer(m)) {
				if (!srtype.equals("void")) {

					StrBuilder msb = new StrBuilder();
					for (NewMap<String, String> m1 : params) {
						String key = (String) m1.getKey();
						String val = (String) m1.getValue();
						String hval = val.hashCode() + "";
						String p = B2G.getMapType(key);
						boolean isOut = B2G.isOut(m, val);
						if (isOut) {
							if (p.equals("getObject")) {
								msb.ap("${1} ${2}, ", key, val);
							}
						}
					}

					sb.pn("    public abstract void on${1}(int cmd, ${2}${3} val);",
							upper1(mname), msb, srtype);
				}
			} else {

				StrBuilder sb1 = new StrBuilder();
				for (NewMap<String, String> m1 : params) {
					String key = (String) m1.getKey();
					String val = (String) m1.getValue();
					if (B2G.getMapType(key).equals("getList")) {
						key = PStr.str("${1}", "ArrayList",
								B2G.getOType(m, m1.getValue().toString()));
					}
					key = key.toLowerCase().equals("boolean") ? "bool" : key;
					key = key.equals("String") ? "string" : key;

					sb1.ap("${1} ${2}, ", key, val);
				}
				if (sb1.length() > 2) {
					sb1.removeRight(2);
				}

				// 需要实现的逻辑函数
				sb.pn("    public abstract ${1} on${2}(int cmd, ${3}) ;",
						srtype, upper1(mname), sb1);

			}
			sb.pn("");
		}
		sb.pn("    }");
		// sb.pn("}");
	}

	public static String upper1(String s) {
		if (s == null || s.isEmpty())
			return s;
		int len = s.length();
		return s.substring(0, 1).toUpperCase() + s.substring(1, len);
	}

	public static String upperS(String s) {
		if (s == null || s.isEmpty())
			return s;
		s = s.toUpperCase();
		return !s.endsWith("S") ? s + "S" : s;
	}

	public static String upper1S(String s) {
		if (s == null || s.isEmpty())
			return s;
		s = upper1(s);
		return !s.endsWith("s") ? s + "s" : s;
	}

	public static void writeFile(String f, String str) {
		try (FileOutputStream out = new FileOutputStream(new File(f));
				OutputStreamWriter osw = new OutputStreamWriter(out,
						Encoding.UTF8);) {
			osw.write(str, 0, str.length());
			osw.close();
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	static String getSheetIndexMethod(String cname, Map map) {
		String type = MapEx.getString(map, "type"); // ix , ux
		List<Map> fields = MapEx.getList(map, "fields");

		String ret = getSheetIndexReturn(cname, type);
		String method = getSheetIndexMethodName(fields);
		String params = getSheetIndeParams(fields);
		StrBuilder sb = new StrBuilder();
		sb.a(ret).a(" ").a(method).a("(").a(params).a(")");
		return sb.str();
	}

	static String getSheetIndexReturn(String cname, String type) {
		if (type.equals("ix")) {
			return "List<" + cname + ">";
		} else if (type.equals("ux")) {
			return cname;
		}

		return "";
	}

	static String getSheetIndexReturnInit(String cname, String type) {
		if (type.equals("ix")) {
			return "new List<" + cname + ">()";
		} else if (type.equals("ux")) {
			return "null";
		}

		return "";
	}

	static String getSheetIndexMethodName(List<Map> list) {
		if (isEmpty(list))
			return "";
		StrBuilder sb = new StrBuilder();
		sb.a("getBy");
		for (Map map : list) {
			String field = MapEx.getString(map, "field");
			String type = MapEx.getString(map, "type");
			String f = upperN1(lower(field));
			sb.a(f);
		}

		return sb.str();
		// [{"field":"GID","type":"int"},{"field":"Lvl","type":"int"}]
		// [{"field":"GID","type":"int"}]
	}

	static String getSheetIndexMethodEq(List<Map> list) {
		if (isEmpty(list))
			return "";
		StrBuilder sb = new StrBuilder();
		for (Map map : list) {
			String field = MapEx.getString(map, "field");
			String type = MapEx.getString(map, "type");
			String flow = lower(field);

			if (type.equals("int")) {
				sb.a("e.").a(field).a(" == ").a(flow).a(" && ");
			} else if (type.equals("long")) {
				sb.a("e.").a(field).a(" == ").a(flow).a(" && ");
			} else if (type.equals("boolean")) {
				sb.a("e.").a(field).a(" == ").a(flow).a(" && ");
			} else if (type.equals("String")) {
				sb.a("e.").a(field).a(".Equals(").a(flow).a(") && ");
			}
		}
		if (sb.len() > 4)
			sb.removeRight(4);
		return sb.str();
		// [{"field":"GID","type":"int"},{"field":"Lvl","type":"int"}]
		// [{"field":"GID","type":"int"}]
	}

	static String getSheetIndeParams(List<Map> list) {
		if (isEmpty(list))
			return "";
		StrBuilder sb = new StrBuilder();
		sb.a("");
		for (Map map : list) {
			String field = MapEx.getString(map, "field");
			String type = MapEx.getString(map, "type");
			String f = lower(field);
			if (type.equals("boolean"))
				type = "bool";
			sb.a(type).a(" ").a(f).a(", ");
		}
		if (sb.len() > 2)
			sb.removeRight(2);
		return sb.str();
		// [{"field":"GID","type":"int"},{"field":"Lvl","type":"int"}]
		// [{"field":"GID","type":"int"}]
	}

	static String getSheetCallParams(List<Map> list) {
		if (isEmpty(list))
			return "";
		StrBuilder sb = new StrBuilder();
		sb.a("");
		for (Map map : list) {
			String field = MapEx.getString(map, "field");
			String f = lower(field);
			sb.a("\"").a(f).a(":\"").a(", ").a(f).a(", ");
		}
		if (sb.len() > 2)
			sb.removeRight(2);
		return sb.str();
		// [{"field":"GID","type":"int"},{"field":"Lvl","type":"int"}]
		// [{"field":"GID","type":"int"}]
	}

	static String getSheetIndexParams(List<Map> list) {
		if (isEmpty(list))
			return "";
		StrBuilder sb = new StrBuilder();
		sb.a("");
		for (Map map : list) {
			String field = MapEx.getString(map, "field");
			String f1 = lower(field);
			sb.a("\"").a(f1).a(":\"").a(", e.").a(field).a(", ");
		}
		if (sb.len() > 2)
			sb.removeRight(2);
		return sb.str();
		// [{"field":"GID","type":"int"},{"field":"Lvl","type":"int"}]
		// [{"field":"GID","type":"int"}]
	}

}
